/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef OHOS_AVCONTROL_COMMAND_H
#define OHOS_AVCONTROL_COMMAND_H

/**
 * @addtogroup avsession
 * @{
 *
 * @brief Provides APIs for audio and video (AV) media control.
 *
 * The APIs can be used to create, manage, and control media sessions.
 *
 * @syscap SystemCapability.Multimedia.AVSession.Core
 * @since 9
 * @version 1.0
 */

/**
 * @file avcontrol_command.h
 *
 * @brief Declares the APIs for setting, obtaining, and cloning AV control commands.
 *
 * @since 9
 * @version 1.0
 */

#include <cinttypes>
#include <functional>
#include <string>
#include <variant>

#include "parcel.h"

namespace OHOS::AVSession {
/**
 * @brief A utility class that describes AV control commands and encapsulates control commands in objects.
 * You can set and obtain control commands through this class.
 */
class AVControlCommand : public Parcelable {
public:
    /**
     * @brief Enumerates the control commands.
     */
    enum {
        /** Invalid value, which is used internally to determine whether a command is valid. */
        SESSION_CMD_INVALID = -1,
        /** Play the media. */
        SESSION_CMD_PLAY = 0,
        /** Pause the playback. */
        SESSION_CMD_PAUSE = 1,
        /** Stop the playback. */
        SESSION_CMD_STOP = 2,
        /** Play the next track. */
        SESSION_CMD_PLAY_NEXT = 3,
        /** Play the previous track. */
        SESSION_CMD_PLAY_PREVIOUS = 4,
        /** Fast-forward. */
        SESSION_CMD_FAST_FORWARD = 5,
        /** Rewind. */
        SESSION_CMD_REWIND = 6,
        /** Seek. */
        SESSION_CMD_SEEK = 7,
        /** Set the playback speed. */
        SESSION_CMD_SET_SPEED = 8,
        /** Set the loop mode. */
        SESSION_CMD_SET_LOOP_MODE = 9,
        /** Favorite the track. */
        SESSION_CMD_TOGGLE_FAVORITE = 10,
        /** Invalid value, which is used internally to determine whether a command is valid. */
        SESSION_CMD_MAX = 11
    };

    AVControlCommand();
    ~AVControlCommand() override;

    /**
     * @brief Unmarshals IPC data from a {@link Parcel} object.
     *
     * @param data Indicates the pointer to the {@link Parcel} object for unmarshalling.
     * @return Returns the pointer to a {@code AVControlCommand} object.
     * @see Marshalling
     * @since 9
     * @version 1.0
     */
    static AVControlCommand *Unmarshalling(Parcel &data);

    /**
     * @brief Marshals IPC data into a {@link Parcel} object.
     *
     * @param parcel Indicates the pointer to the {@link Parcel} object for marshalling.
     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
     * @see Unmarshalling
     * @since 9
     * @version 1.0
     */
    bool Marshalling(Parcel &parcel) const override;

    /**
     * @brief Checks whether this control command is within the valid range.
     *
     * @return Returns <b>true</b> if the control command is within the valid range, that is, 
     * from {@link #SESSION_CMD_INVALID} to @{link #SESSION_CMD_MAX};
     * returns <b>false<\b> otherwise.
     * @since 9
     * @version 1.0
     */
    bool IsValid() const;

    /**
     * @brief Sets a control command.
     *
     * @param cmd Indicates the control command to set, which must be within the range
     * from {@link #SESSION_CMD_INVALID} to {@link #SESSION_CMD_MAX}.
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @see GetCommand
     * @since 9
     * @version 1.0
     */
    int32_t SetCommand(int32_t cmd);

    /**
     * @brief Obtains the control command.
     *
     * @return Returns the control command, which is within the range
     * from {@link #SESSION_CMD_INVALID} to {@link #SESSION_CMD_MAX}.
     * @see SetCommand
     * @since 9
     * @version 1.0
     */
    int32_t GetCommand() const;

    /**
     * @brief Sets a playback speed.
     *
     * @param speed Indicates the playback speed to set. The value must be greater than <b>0</b>.
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @see GetSpeed
     * @since 9
     * @version 1.0
     */
    int32_t SetSpeed(double speed);

    /**
     * @brief Obtains the playback speed.
     *
     * @param speed Indicates the pointer to the playback speed.
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @see SetSpeed
     * @since 9
     * @version 1.0
     */
    int32_t GetSpeed(double &speed) const;

    /**
     * @brief Sets the time to seek to.
     *
     * @param time Indicates the time to seek to, which is calculated from the beginning of the media asset, in ms.
     * The value must be greater than or equal to <b>0</b>.
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @see GetSeekTime
     * @since 9
     * @version 1.0
     */
    int32_t SetSeekTime(int64_t time);

    /**
     * @brief Obtains the time to seek to.
     *
     * @param time Indicates the pointer to the time to seek to, which is calculated from the beginning of the media asset,
     * in ms. The value must be greater than or equal to <b>0</b>.
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @see SetSeekTime
     * @since 9
     * @version 1.0
     */
    int32_t GetSeekTime(int64_t &time) const;

    /**
     * @brief Sets a loop mode.
     *
     * @param mode Indicates the loop mode to set, which must be within the range
     * from {@link AVPlaybackState#LOOP_MODE_SEQUENCE} to {@link AVPlaybackState#LOOP_MODE_SHUFFLE}.
     * @see GetLoopMode
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @since 9
     * @version 1.0
     */
    int32_t SetLoopMode(int32_t mode);

    /**
     * @brief Obtains the loop mode.
     *
     * @param mode Indicates the pointer to the loop mode,which is within the range
     * from {@link AVPlaybackState#LOOP_MODE_SEQUENCE} to {@link AVPlaybackState#LOOP_MODE_SHUFFLE}.
     * @see SetLoopMode
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @since 9
     * @version 1.0
     */
    int32_t GetLoopMode(int32_t &mode) const;

    /**
     * @brief Sets a media asset ID.
     *
     * @param assetId Indicates the pointer to the asset ID to set, which cannot be null.
     * @see GetAssetId
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @since 9
     * @version 1.0
     */
    int32_t SetAssetId(const std::string &assetId);

    /**
     * @brief Obtains the media asset ID.
     *
     * @param assetId Indicates the pointer to the asset ID.
     * @see SetAssetId
     * @return Returns {@link #AVSESSION_SUCCESS} if the operation is successful; returns an error code otherwise.
     * @since 9
     * @version 1.0
     */
    int32_t GetAssetId(std::string &assetId) const;

     /**
     * @brief Defines a command array, which is used for distributed services
     * to determine whether a control command is supported.
     *
     * @since 9
     * @version 1.0
     */
    const static inline std::vector<int32_t> localCapability {
        SESSION_CMD_PLAY,
        SESSION_CMD_PAUSE,
        SESSION_CMD_STOP,
        SESSION_CMD_PLAY_NEXT,
        SESSION_CMD_PLAY_PREVIOUS,
        SESSION_CMD_FAST_FORWARD,
        SESSION_CMD_REWIND,
        SESSION_CMD_SEEK,
        SESSION_CMD_SET_SPEED,
        SESSION_CMD_SET_LOOP_MODE,
        SESSION_CMD_TOGGLE_FAVORITE,
    };

private:
    /** Value corresponding to the control command {@link #SESSION_CMD_INVALID}. */
    int32_t cmd_ = SESSION_CMD_INVALID;
    /** Values corresponding to the control commands
     * {@link #SetLoopMode}, {@link #SetSeekTime}, {@link #SetSpeed}, and {@link #SetAssetId}.
     */
    std::variant<int32_t, double, int64_t, std::string> param_;
};
}
/** @} */
#endif // OHOS_AVCONTROL_COMMAND_H
